package com.ml4ai.backend.services.base.impl;

import com.ml4ai.backend.domain.base.BaseAuditEntity;
import com.ml4ai.backend.dto.base.BaseAuditDTO;
import com.ml4ai.backend.repository.EntityRepository;
import com.ml4ai.backend.services.base.BaseService;
import com.ml4ai.backend.utils.QueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.repository.JpaRepository;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by uesr on 2018/9/2.
 */
public abstract class BaseServiceImpl<T extends BaseAuditEntity, K extends BaseAuditDTO> implements BaseService<T, K> {

    protected Class<T> entityClazz;

    @Autowired
    protected EntityRepository entityRepository;

    public BaseServiceImpl() {
        entityClazz = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public abstract JpaRepository<T, Long> getRepository();

    public abstract Function<T, K> getConvertEntity2DTOFunction();

    public abstract Function<K, T> getConvertDTO2EntityFunction();

    @Override
    public K findById(Long id) {
        T t = getRepository().getOne(id);
        if (t != null) {
            return getConvertEntity2DTOFunction().apply(t);
        } else {
            return null;
        }
    }

    @Override
    public K save(K k) {
        T t = getConvertDTO2EntityFunction().apply(k);
        t = getRepository().save(t);
        return getConvertEntity2DTOFunction().apply(t);
    }

    @Override
    public Boolean delete(Long id) {
        try {
            T t = getRepository().getOne(id);
            t.setStatus("0");
            getRepository().save(t);
            return true;
        } catch (Exception excep) {
            return false;
        }
    }

    @Override
    public List<K> query(Object k) {
        return entityRepository.query(entityClazz, QueryBuilder.buildQuery(k), null).stream().map(getConvertEntity2DTOFunction()).collect(Collectors.toList());
    }

    @Override
    public Page<K> queryPage(Object k, Pageable pageable) {
        List<T> list = entityRepository.queryPageList(entityClazz, pageable, QueryBuilder.buildQuery(k), null);
        return new PageImpl<>(list,
                pageable, entityRepository.queryCount(entityClazz, QueryBuilder.buildQuery(k))
        ).map(getConvertEntity2DTOFunction()::apply);
    }

    @Override
    public Long count(Object k) {
        return entityRepository.queryCount(entityClazz, QueryBuilder.buildQuery(k));
    }
}
